home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacPeople 2001 February 15
/
MACPEOPLE-2001-02-15.ISO.7z
/
MACPEOPLE-2001-02-15.ISO
/
オンラインウエア
/
厳選オンラインウエア100
/
グラフィック
/
六角大王55.sit
/
Roku55 Folder
/
技術解説プログラム
< prev
next >
Wrap
Text File
|
1993-11-14
|
10KB
|
419 lines
/**********************************************************************
面対称物体の2次元座標から3次元座標を求めるプログラム
Copyright (C) 1993 Shusaku Furushima.
注意:このプログラムはこのままでは動作しません。内容を理解した上で
各関数/オブジェクトをご自分のプログラムで使うようにしてください。
このソースリストの一部または全部をあなたのプログラム(営利目的の物を含む)で
利用することを許可します。
**********************************************************************/
#include <stdio.h>
#include <math.h>
#define fudou double
/* max point of qr bunkai */
#define RQRMP 10
#define RQRNP 30
/******** Rcoord ********/
typedef struct {
fudou x;
fudou y;
fudou z;
} Rcoord;
/******** 4 x 4 matrix **********/
typedef fudou Rmat[4][4];
/********** mathematical functions ********/
extern void Rqrbunkai(int m,int n,fudou qa[][RQRNP],
fudou qy[],fudou qz[]);
/******** general 4x4 matrix *********/
class Rmat44{
void initmat(Rmat amat);
public:
void matmul(Rmat mat2);
Rmat mat;
void IRmat44();
void rotp(fudou p);
void rotq(fudou p);
void rotr(fudou p);
void copyfrom(Rmat mat2);
void move(fudou x, fudou y, fudou z);
void bepers();
void mul(fudou x, fudou y, fudou z);
void getcoord2(Rcoord *coord, Rcoord *cd, int pers);
};
/********* 4x4 matrix for display objects *********/
class Rmatobj{
public:
Rmat44 *devmat; /* matrix of [3D -> 2D screen] */
Rmat44 *symm; /* symmetrical matrix of devmat */
fudou pp, pq, pr; /* rotate angle */
fudou dx, dy, dz; /* move coordinate */
fudou bx, by; /* scale to screen 2d coord */
int pers; /* flag if pers:1 or ortho:0 */
void IRmatobj(); /* init matrixes */
void makedev(); /* make devmat */
void setsymmatx(); /* set symm matrix of devmat */
Rcoord getdev(Rcoord *pt); /* get screen coord */
Rcoord calc3d(Rcoord *pt1, Rcoord *pt2); /* get 3D coord from 2D coord */
};
/********** least square method by QR (without pivoting) ***********/
/* 「最小自乗法」(条件が冗長である連立方程式の解法)を解く関数 */
/********* qrbunkai simple version ********/
/* m number of unknown param. */
/* n number of data sets. */
/* qa data param matrix. */
/* qy data value vector. */
/* qz returning answer. */
/* qrnp define value of points number. */
/* qrmp define value of param number. */
/******************************************/
void Rqrbunkai(int m,int n,fudou qa[][RQRNP],
fudou qy[],fudou qz[])
{
int i,j,k;
static fudou a,qq[RQRMP][RQRNP],rq[RQRMP][RQRMP];
for( k = 1; k <= m; k++)
{
a = 0;
for(i = 1; i <=n; i++)
a = a + qa[k][i] * qa[k][i];
rq[k][k] = sqrt(a);
for( i = 1; i <= n; i++)
qq[k][i] = qa[k][i] / rq[k][k];
for( j = k+1; j <= m; j++)
{
a = 0;
for( i = 1; i <= n; i++)
a = a + qq[k][i] * qa[j][i];
rq[j][k] = a;
for( i = 1; i <= n; i++)
qa[j][i] = qa[j][i] - qq[k][i] * rq[j][k];
}
}
for( i = 1; i <= m; i++)
{
a = 0;
for( j = 1; j <= n; j++)
a = a + qq[i][j] * qy[j];
qz[i] = a;
}
qz[m] = qz[m] / rq[m][m];
for( i = m - 1; i >= 1; i--)
{
for( j = i + 1; j <= m; j++)
qz[i] = qz[i] - qz[j] * rq[j][i];
qz[i] = qz[i] / rq[i][i];
}
}
/******** mathod for general matrix Rmat44 *********/
/* 4X4行列を扱う一般的な method 群 */
/*** initialise matrix ***/
void Rmat44::IRmat44()
{
initmat(mat);
}
/*** set [I] matrix ***/
void Rmat44::initmat(Rmat amat)
{
int i, j;
for (i = 0; i < 4; i++){
for (j = 0; j < 4; j++){
amat[i][j] = 0.0;
if (i == j)
amat[i][j] = 1.0;
}
}
}
/*** rotate around Y axis ***/
void Rmat44::rotp(fudou p)
{
Rmat tmp;
initmat(tmp);
tmp[0][0] = cos(p);
tmp[2][0] = sin(p);
tmp[0][2] = - sin(p);
tmp[2][2] = cos(p);
matmul(tmp);
}
/*** rotate around X axis ***/
void Rmat44::rotq(fudou p)
{
Rmat tmp;
initmat(tmp);
tmp[1][1] = cos(p);
tmp[2][1] = -sin(p);
tmp[1][2] = sin(p);
tmp[2][2] = cos(p);
matmul(tmp);
}
/*** rotate around Z axis ***/
void Rmat44::rotr(fudou p)
{
Rmat tmp;
initmat(tmp);
tmp[0][0] = cos(p);
tmp[1][0] = -sin(p);
tmp[0][1] = sin(p);
tmp[1][1] = cos(p);
matmul(tmp);
}
/*** shift coord ***/
void Rmat44::move(fudou x, fudou y, fudou z)
{
Rmat tmp;
initmat(tmp);
tmp[0][3] = x;
tmp[1][3] = y;
tmp[2][3] = z;
matmul(tmp);
}
/*** set to perspective matrix ***/
void Rmat44::bepers()
{
Rmat tmp;
initmat(tmp);
/* project plane is always z=1 and eye point is x=y=z=0 */
tmp[3][2] = 1.0;
matmul(tmp);
}
/*** magnify value ***/
void Rmat44::mul(fudou x, fudou y, fudou z)
{
Rmat tmp;
initmat(tmp);
tmp[0][0] = x;
tmp[1][1] = y;
tmp[2][2] = z;
matmul(tmp);
}
/*** multiple two matrices ***/
void Rmat44::matmul(Rmat mat2)
{
int i, j, k;
Rmat tmp;
for (i = 0; i < 4; i++){
for (j = 0; j < 4; j++){
tmp[i][j] = mat[i][j];
}
}
for (i = 0; i < 4; i++){
for (j = 0; j < 4; j++){
mat[i][j] = 0.0;
for (k = 0; k < 4; k++){
mat[i][j] += tmp[k][j] * mat2[i][k];
}
}
}
}
/*** copy matrix ***/
void Rmat44::copyfrom(Rmat mat2)
{
int i,j;
for (i = 0; i < 4; i++){
for (j = 0; j < 4; j++){
mat[i][j] = mat2[i][j];
}
}
}
/*** get 2D coord from 3D coord from the matrix ***/
void Rmat44::getcoord2(Rcoord *coord, Rcoord *cd, int pers)
{
int i,j;
fudou w;
coord->x = mat[0][0] * cd->x + mat[0][1] * cd->y +
mat[0][2] * cd->z + mat[0][3];
coord->y = mat[1][0] * cd->x + mat[1][1] * cd->y +
mat[1][2] * cd->z + mat[1][3];
coord->z = 0.0;
if (pers){
w = mat[3][0] * cd->x + mat[3][1] * cd->y +
mat[3][2] * cd->z + mat[3][3];
w = 1.0 / w;
coord->x *= w;
coord->y *= w;
}
}
/************* method for Roku matrix Rmatobj **************/
/* 六角大王用の行列操作 method 群 */
/*** initialise matrices ***/
void Rmatobj::IRmatobj()
{
devmat = new(Rmat44);
symm = new(Rmat44);
devmat->IRmat44();
symm->IRmat44();
/*** You can change these values in your application ***/
pp = -0.9; /* default angle */
pq = -0.25;
pr = 0.0;
dx = 0.0; /* default position */
dy = 0.0;
dz = 1.5;
bx = by = 100.0; /* default magnify value */
pers = 1; /* default is perspective (not orthogonal) */
}
/*** make matrix of [3D coord -> 2D screen coord] ***/
void Rmatobj::makedev()
{
devmat->IRmat44();
devmat->rotp(pp); /* rotate around Y axis */
devmat->rotq(pq); /* rotate around X axis */
devmat->rotr(pr); /* rotate around Z axis */
devmat->move(dx, dy, dz); /* shift position */
if (pers)
devmat->bepers(); /* set to perspective matrix */
dsmat->mul(bx, by, 1.0); /* magnify to be screen scale */
}
/*** get 2D screen coord from 3D coord ***/
Rcoord Rmatobj::getdev(Rcoord *pt)
{
Rcoord tmp;
devmat->getcoord2 (&tmp, pt, pers);
return(tmp);
}
/*** set plane symmetry matrix ***/
void Rmatobj::setsymmatx()
{
symm->IRmat44();
symm->mat[0][0] = - 1.0;
symm->matmul(devmat->mat);
}
/*** calc 3D coord from two 2D coord ***/
Rcoord Rmatobj::calc3d(Rcoord *pt1, Rcoord *pt2)
{
Rcoord p;
fudou qa[RQRMP][RQRNP], qy[RQRNP], qz[RQRMP];
qa[1][1] = devmat->mat[0][0] - devmat->mat[3][0] * pt1->x;
qa[2][1] = devmat->mat[0][1] - devmat->mat[3][1] * pt1->x;
qa[3][1] = devmat->mat[0][2] - devmat->mat[3][2] * pt1->x;
qy[1] = - devmat->mat[0][3] + devmat->mat[3][3] * pt1->x;
qa[1][2] = devmat->mat[1][0] - devmat->mat[3][0] * pt1->y;
qa[2][2] = devmat->mat[1][1] - devmat->mat[3][1] * pt1->y;
qa[3][2] = devmat->mat[1][2] - devmat->mat[3][2] * pt1->y;
qy[2] = - devmat->mat[1][3] + devmat->mat[3][3] * pt1->y;
qa[1][3] = symm->mat[0][0] - symm->mat[3][0] * pt2->x;
qa[2][3] = symm->mat[0][1] - symm->mat[3][1] * pt2->x;
qa[3][3] = symm->mat[0][2] - symm->mat[3][2] * pt2->x;
qy[3] = - symm->mat[0][3] + symm->mat[3][3] * pt2->x;
qa[1][4] = symm->mat[1][0] - symm->mat[3][0] * pt2->y;
qa[2][4] = symm->mat[1][1] - symm->mat[3][1] * pt2->y;
qa[3][4] = symm->mat[1][2] - symm->mat[3][2] * pt2->y;
qy[4] = - symm->mat[1][3] + symm->mat[3][3] * pt2->y;
Rqrbunkai(3, 4, qa, qy, qz);
p.x = qz[1];
p.y = qz[2];
p.z = qz[3];
return(p);
}
/************** abstract of RokkakuDaioh 2D -> 3D routine *****************/
/*** 2次元座標から3次元座標を計算する処理の流れ ***/
/* 本物の六角大王ではデータはリストで持っています */
/* クリッピングは本物の六角大王でもやっていません! */
void main()
{
Rmatobj *rmat;
Rcoord gridscpt[MAX], gridpt[MAX]; /* グリッドのデータ */
int ngpoint, ngline, gridline[MAX][2];
Rcoord inputscpt[MAX][2], inputpt[MAX][2]; /* 入力する線画のデータ */
int ninputpt, ninputln, inputline[MAX][2];
short x, y;
int i;
:
グリッドの座標と線情報を設定する。
六角大王では一辺 1.0 で、各辺が x,y,z 軸に平行な立方体を定義している。
:
rmat = new(Rmatobj);
rmat->IRmatobj(); /* 行列の初期化 */
:
表示パラメータ(rmat->pp など)を好みに合わせて変える。
:
rmat->makedev(); /* パラメータから透視変換行列を求める */
for (i = 0; i < ngpoint; i++){ /* グリッドの表示座標を計算 */
gridscpt[i] = rmat->getdev(&gridpt[i]);
}
for (i = 0; i < ngline; i++){ /* グリッドをスクリーンに表示 */
x = (short)(gridscpt[ gridline[i][0] ].x);
y = (short)(gridscpt[ gridline[i][0] ].y);
MoveTo(x, y);
x = (short)(gridscpt[ gridline[i][1] ].x);
y = (short)(gridscpt[ gridline[i][1] ].y);
LineTo(x, y);
}
:
グリッドに合わせた物体の線画を入力させる。
入力された点の左右の対応づけが行われた結果、
左側の点のスクリーン上の座標が inputscpt[i][0] に、
右側の点のスクリーン上の座標が inputscpt[i][1] に入る。
(x,y,z のうち x,y だけに値が入っていればよい)
:
rmat->setsymmatx(); /* 対称な行列を設定 */
for (i = 0; i < ninputpt; i++){
/* 3次元座標を計算 */
inputpt[i][0] = rmat->calc3d(&inputscpt[i][0], &inputscpt[i][1]);
/* 一方の点は X 座標の符号が逆 */
inputpt[i][1] = inputpt[i][0];
inputpt[i][1].x = - inputpt[i][1].x;
}
:
これにて、
左側の点の3次元座標が inputpt[i][0] に、
右側の点の3次元座標が inputpt[i][1] に入っている。
}